`timescale 1ns / 100ps

module i2c_slave (
	input clk,
	input rst_n,
	input reg_read_value,
	
	output [7:0] slave_addr,
	output [7:0] reg_addr,
	output [7:0] reg_value,
	
	inout scl,
	inout sda
);

reg [7:0] slave_addr;
reg [7:0] reg_addr;
reg [7:0] reg_value;

reg scl_out;
reg scl_in;
reg sda_out;
reg sda_in;
reg scl_in_d0;
reg sda_in_d0;

assign scl = scl_out?1'bz:0;
assign sda = sda_out?1'bz:0;

reg [7:0] delay_count;
reg [7:0] state;
reg [7:0] g_state;

assign scl_posedge = (!scl_in_d0)&(scl_in);
assign scl_negedge = (scl_in_d0)&(!scl_in);
assign sda_posedge = (!sda_in_d0)&(sda_in);
assign sda_negedge = (sda_in_d0)&(!sda_in);


reg [7:0] readByte;
reg [7:0] readMask;

task i2c_readByte;
	case (state)
		0,1,2,3,4,5,6,7: begin
			if(scl_posedge) begin
				if(sda_in) begin
					readByte <= readByte | readMask;
				end
				readMask <= readMask>>1;
				state <= state+1;
			end
		end
		8: begin
			if(scl_negedge) begin
				sda_out <= 0;
				state <= state+1;
			end
		end
		9: begin
			if(scl_negedge) begin
				sda_out <= 1;
				state <= state+1;
			end
		end
	endcase
endtask

task i2c_writeByte;
	case (state)
		0: begin
			if(readByte & readMask) begin
				sda_out <= 1;
			end
			else begin
				sda_out <= 0;
			end
			readMask <= readMask >> 1;
			state <= state+1;
		end
		1,2,3,4,5,6,7: begin
			if(scl_negedge) begin
				if(readByte & readMask) begin
					sda_out <= 1;
				end
				else begin
					sda_out <= 0;
				end
				readMask <= readMask >> 1;
				state <= state+1;
			end
		end
		8: begin
			if(scl_negedge) begin
				sda_out <= 1;
				state <= state+1;
			end
		end
		9: begin
			if(scl_posedge) begin
				if(sda_in) begin
					state <= state+1;
				end
				else begin
					state <= 11;
				end
			end
		end
		10: begin // end write reg				
		end
		11: begin // continue write reg
		end
		
	endcase
endtask

always @ (posedge clk)
begin
	if(!rst_n) begin
		scl_out <= 1;
		sda_out <= 1;
		delay_count <= 0;
		state <= 0;
		g_state <= 0;
		slave_addr <= 0;
		reg_addr <= 0;
		reg_value <= 0;
	end
	else begin
		scl_in <= scl;
		sda_in <= sda;
		scl_in_d0 <= scl_in;
		sda_in_d0 <= sda_in;
		if(scl_in & sda_negedge) begin
			g_state <= 1; // start
		end
		else if(scl_in & sda_posedge) begin
			g_state <= 0; // stop
		end
		else begin
			case (g_state)
				0: begin // stop
				end
				1: begin // start
					state <= 0;
					readMask <= 8'h80;;
					readByte <= 0;
					g_state <= g_state+1;
				end
				2: begin // read slave address
					i2c_readByte();
					if(state == 10) begin
						
						slave_addr <= readByte;
						if(readByte[0]) begin							
							g_state <= 10;
							readByte <= 8'h34;
							state <= 0;
							readMask <= 8'h80;	
						end
						else begin						
							state <= 0;
							readMask <= 8'h80;;
							readByte <= 0;
							g_state <= g_state+1;
						end
					end
				end
				3: begin // read reg address
					i2c_readByte();
					if(state == 10) begin
						g_state <= g_state+1;
						reg_addr <= readByte;
						state <= 0;
						readMask <= 8'h80;;
						readByte <= 0;
					end
				end
				4: begin // read reg value
					i2c_readByte();
					if(state == 10) begin
						g_state <= g_state+1;
						reg_value <= readByte;
						state <= 0;
						readMask <= 8'h80;;
						readByte <= 0;
					end
				end
				
				// write reg value				
				10: begin
					i2c_writeByte();					
				end
				
			endcase
		end
		
	end
end


endmodule